<?php
namespace WDB\Query;
use WDB;

/**
 *
 * @author Richard Ejem <richard(at)ejem.cz>
 * @package WDB
 */
class CachedSelect extends \WDB\BaseObject implements \Countable
{
    /**@var Select*/
    protected $select;
    /**@var Select*/
    protected $origSelect;
    /**@var SelectCache*/
    protected $cache;
    
    /**
     * @param Select
     */
    public function __construct(Select $select = NULL)
    {
        $this->origSelect = $select === NULL ? NULL : clone $select;
        $this->select = $select;
        $this->cache = new SelectCache();
    }
    
    /**
     * Changes internal select query object
     *
     * @param Select
     */
    public function setSelect(Select $select)
    {
        $this->select = $select;
    }
    
    /**
     * Returns internal select query object
     *
     * @return Select
     */
    public function getSelect()
    {
        return $this->select;
    }
    
    /**
     * shortcut to getResult()
     * 
     * @return int|NULL
     * @throws WDB\Exception\InvalidOperation
     */
    public function __invoke()
    {
        return $this->getResult();
    }
    
    /**
     * Get cached select result if already queried for data or bound select object was not changed,
     * otherwise queries for data and caches result
     *
     * @return iSelectResult|NULL
     * @throws WDB\Exception\InvalidOperation
     */
    public function getResult()
    {
        if (!$this->select instanceof Select) throw new WDB\Exception\InvalidOperation("getting data from a cached select without setting select query");
        if (serialize($this->select) != serialize($this->origSelect))
        {
            $this->cache->result = $this->select->run();
            $this->cache->count = NULL;
            $this->origSelect = clone $this->select;
        }
        elseif ($this->cache->result === NULL)
        {
            $this->cache->result = $this->select->run();
        }
        return $this->cache->result;
    }
    
    /**
     * Get count of records in cached select result if already queried for data or bound select object was not changed,
     * otherwise queries for data and caches result
     *
     * @return int|NULL
     * @throws WDB\Exception\InvalidOperation
     */
    public function getCount()
    {
        if (!$this->select instanceof Select) throw new WDB\Exception\InvalidOperation("getting data from a cached select without setting select query");
        if (serialize($this->select) != serialize($this->origSelect))
        {
            $this->cache->count = $this->select->count();
            $this->cache->result = NULL;
            $this->origSelect = clone $this->select;
        }
        elseif ($this->cache->count === NULL)
        {
            $this->cache->count = $this->select->count();
        }
        return $this->cache->count;
    }
    
    // <editor-fold defaultstate="collapsed" desc="\Countable impl.">
    
    /**
     * synonym for getCount() for \Countable interface
     *
     * @return int|NULL
     * @throws WDB\Exception\InvalidOperation
     */
    public function count()
    {
        return $this->getCount();
    }
    // </editor-fold>
}
